<!doctype html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>canvas压缩图片</title>
	</head>

	<!-- https://www.zhangxinxu.com/wordpress/2017/07/html5-canvas-image-compress-upload/ -->
	<!-- https://mp.weixin.qq.com/s/vdikyjwFhxP0RrtbcGwoLw -->

	<body>
		<input type="file" />
		<canvas id="ctx"></canvas>
		<button id="btn">下载</button>

		<script>
			const c = document.querySelector('#ctx');
			const ctx = c.getContext('2d');
			const reader = new FileReader();
			const img = new Image();

			// 图片数据转data数据完回调
			reader.onload = async function (e) {
				img.src = e.target.result;
			};

			// 图片加载完回调
			img.onload = function () {
				c.width = this.width;
				c.height = this.height;
				ctx.drawImage(img, 0, 0, this.width, this.height);
			};

			// 选择图片
			document.querySelector([(type = 'input')]).addEventListener('change', e => {
				reader.readAsDataURL(event.target.files[0]);
			});

			// 下载
			document.querySelector('#btn').addEventListener('click', e => {
				// 方法一 适用于本地 压缩率在0.2~0.5之间压缩率最大，对原图影响不大，
				const res = c.toDataURL('image/jpeg', 0.5);
				console.log(res);

				// 方法二 适用于上传 是异步的
				// c.toBlob(function (blob) {
				//   console.log(blob);
				// });

				let a = document.createElement('a');
				a.href = res;
				a.download = 'canvas-img';
				a.click();
				a = null;
			});

			/**
			 * 压缩方法
			 * @param {string} file 文件
			 * @param {Number} quality  0~1之间
			 */
			function compressImg(file, quality) {
				if (file[0]) {
					return Promise.all(Array.from(file).map(e => compressImg(e, quality))); // 如果是 file 数组返回 Promise 数组
				} else {
					return new Promise(resolve => {
						const reader = new FileReader(); // 创建 FileReader
						reader.onload = ({ target: { result: src } }) => {
							const image = new Image(); // 创建 img 元素
							image.onload = async () => {
								const canvas = document.createElement('canvas'); // 创建 canvas 元素
								canvas.width = image.width;
								canvas.height = image.height;
								canvas.getContext('2d').drawImage(image, 0, 0, image.width, image.height); // 绘制 canvas
								const canvasURL = canvas.toDataURL('image/jpeg', quality);
								const buffer = atob(canvasURL.split(',')[1]);
								let length = buffer.length;
								const bufferArray = new Uint8Array(new ArrayBuffer(length));
								while (length--) {
									bufferArray[length] = buffer.charCodeAt(length);
								}
								const miniFile = new File([bufferArray], file.name, {
									type: 'image/jpeg',
								});
								resolve({
									file: miniFile,
									origin: file,
									beforeSrc: src,
									afterSrc: canvasURL,
									beforeKB: Number((file.size / 1024).toFixed(2)),
									afterKB: Number((miniFile.size / 1024).toFixed(2)),
								});
							};
							image.src = src;
						};
						reader.readAsDataURL(file);
					});
				}
			}
		</script>
	</body>
</html>
